package com.nit.tools.doc;

import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import com.nit.tools.document.PdfTools;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xwpf.usermodel.*;

import java.io.*;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


/**
 * @description: 工具类
 */
@Slf4j
public class WordUtils {

    public static void main(String[] args) {
        try {
//            String srcfile = "D://11.docx";
//            String destfile = "D://22.pdf";

            String srcfile = "/opt/11.docx";
            String destfile = "/opt/22.pdf";
            WordUtils.convertToPDF(srcfile, destfile);

            String imgPath = "/opt/imm/doc";
            PdfTools.loadPdf2Image(imgPath, destfile, 300, "jpg");


            /**
             * 填充word并生成pdf
             * @throws Exception
             */

            //填充word 需要在文档定义： ${name}
//            Map<String, Object> strData = new HashMap<>();
//            strData.put("${name}", "xxx"); //客户名称
//            strData.put("${createDate}", "2021-01-01");
////            strData.put("${openingAccountBalance}", 121);//期初账户余额（元）
////            strData.put("${rechargeAmount}", 121);//新增充值金额（元）
////            strData.put("${totalConsumptionAmount}", 121);//本账期内消费（元）
////            strData.put("${balanceAfterSettlement}", 121);//期末账户余额（元）
//            String readPath = "D://doc//template.docx"; //word模板
//            String outPath = "D://doc//output.docx"; //输出填充word路径
//            String outPdfPath = "D://doc//output.pdf"; //输入word转pdf路径
//            WordUtils.compile(readPath, outPath, strData); //填充word，如果只要word转pdf这里可以不要

            // 转换操作，可单独使用
//            WordUtils.convertToPDF(outPath, outPdfPath); //word转pdf
//            WordUtils.execute(outPdfPath); //pdf转图片png


//            WordUtils.docTopdf("d://11.doc", "D://11.pdf");
//            WordUtils.docTopdf("d://222.xlsx", "D://222.pdf");


        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * @param path    模版路径
     * @param outPath 输出路径
     * @param dict    需要替换的信息集合
     * @Date: 2023/2/20 17:42
     * @Return: boolean
     * @description: 根据dict编译模版中的文本和表格
     */
    public static void compile(String path, String outPath, Map<String, Object> dict) throws Exception {
        FileInputStream is = new FileInputStream(path);
        XWPFDocument document = new XWPFDocument(is);
        if (dict != null) {
            // 替换掉表格之外的文本(仅限文本)
            WordUtils.compileText(document, dict);
            // 替换表格内的文本对象
            WordUtils.compileTable(document, dict);
        }
        File f = new File(outPath.substring(0, outPath.lastIndexOf(File.separator)));
        if (!f.exists()) {
            f.mkdirs();
        }
        FileOutputStream out = new FileOutputStream(outPath);
        document.write(out);


    }

    /***
     * @Description :替换段落文本
     * @param document docx解析对象
     * @param dict 需要替换的信息集合
     * @return void
     * @Date 2022/11/17 17:22
     */
    public static void compileText(XWPFDocument document, Map<String, Object> dict) {
        // 获取段落集合
        Iterator<XWPFParagraph> iterator = document.getParagraphsIterator();
        XWPFParagraph paragraph = null;
        while (iterator.hasNext()) {
            paragraph = iterator.next();
            // 判断此段落是否需要替换
            if (checkText(paragraph.getText())) {
                replaceValue(paragraph, dict);
            }
        }
    }

    /***
     * @Description :替换表格内的文字
     * @param document
     * @param dict 需要替换的信息集合
     * @return void
     * @Date 2022/11/18 11:29
     */
    public static void compileTable(XWPFDocument document, Map<String, Object> dict) {
        // 获取文件的表格
        Iterator<XWPFTable> tableList = document.getTablesIterator();
        XWPFTable table;
        List<XWPFTableRow> rows;
        List<XWPFTableCell> cells;
        // 循环所有需要进行替换的文本，进行替换
        while (tableList.hasNext()) {
            table = tableList.next();
            if (checkText(table.getText())) {
                rows = table.getRows();
                // 遍历表格，并替换模板
                for (XWPFTableRow row : rows) {
                    cells = row.getTableCells();
                    for (XWPFTableCell cell : cells) {
                        // 判断单元格是否需要替换
                        if (checkText(cell.getText())) {
                            List<XWPFParagraph> paragraphs = cell.getParagraphs();
                            for (XWPFParagraph paragraph : paragraphs) {
                                replaceValue(paragraph, dict);
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * @param paragraph word文本
     * @param dict      需要替换的信息集合
     * @Date: 2023/2/20 17:31
     * @description: 替换字符串
     */
    private static void replaceValue(XWPFParagraph paragraph, Map<String, Object> dict) {
        String nextLine;
        List<XWPFRun> runs = paragraph.getRuns();
        for (int i = 0; i < runs.size(); i++) {
            // 读取当前行
            String readLine = runs.get(i).text();
//            System.out.println("readLine:" + readLine);
            // 如果为空 或 不包含目标字符串 则跳过
            if (null == readLine || !readLine.contains("$"))
                continue;
            // 初始化结果集
            StringBuffer sb = new StringBuffer();
            // 循环处理当前行的模版串
            while (readLine.contains("$")) {
                // 获取模版串左侧字符串
                int left;
                if (readLine.contains("${")) {
                    left = readLine.indexOf("${");
                } else {
                    if (runs.size() < i + 1) {
                        break;
                    }
                    nextLine = runs.get(i + 1).text();
                    if (!nextLine.startsWith("{")) break;
                    readLine += nextLine;
                    paragraph.removeRun(i + 1);
                    left = readLine.indexOf("${");
                }
                sb.append(readLine.substring(0, left));
                // 获取模版串右侧
                while (runs.size() >= i + 1 && !readLine.contains("}")) {
                    nextLine = runs.get(i + 1).text();
                    readLine += nextLine;
                    paragraph.removeRun(i + 1);
                }
                int right = readLine.indexOf("}");
                if (right == -1) break;
                // 替换模版串 [如果字典中不存在 则替换为空串]
                sb.append(dict.getOrDefault(readLine.substring(left, right + 1), ""));
                if (right + 1 < readLine.length()) {
                    sb.append(readLine.substring(right + 1));
                }
                readLine = sb.toString();
            }
            runs.get(i).setText(sb.toString(), 0);
        }
    }


    /***
     * @Description :检查文本中是否包含指定的字符(此处为“$”)
     * @param text
     * @return boolean
     * @Date 2022/11/17 17:22
     */
    private static boolean checkText(String text) {
        return text.contains("$");
    }


    /**
     * 通过documents4j 实现word转pdf
     *
     * @param sourcePath 源文件地址 如 /root/example.doc
     * @param targetPath 目标文件地址 如 /root/example.pdf
     */
    public static void documents4jWordToPdf(String sourcePath, String targetPath) {
        File inputWord = new File(sourcePath);
        File outputFile = new File(targetPath);
        try {
            InputStream docxInputStream = new FileInputStream(inputWord);
            OutputStream outputStream = new FileOutputStream(outputFile);
            IConverter converter = LocalConverter.builder().build();
            boolean execute = converter.convert(docxInputStream)
                    .as(DocumentType.DOCX)
                    .to(outputStream)
                    .as(DocumentType.PDF).schedule().get();
            outputStream.close();
            docxInputStream.close();

            log.info("转换完毕 targetPath = {}", outputFile.getAbsolutePath());
            System.out.println("转换完毕 targetPath = " + outputFile.getAbsolutePath());
            converter.shutDown();
            return;
        } catch (Exception e) {
            log.error("[documents4J] word转pdf失败:{}", e.toString());
        }
    }

    /**
     * docx、xlsx、转pdf
     *
     * @param docPath
     * @param pdfPath
     * @return
     */
    public static boolean docTopdf(String docPath, String pdfPath) {

        File inputWord = new File(docPath);
        File outputFile = new File(pdfPath);
        try {
            InputStream docxInputStream = new FileInputStream(inputWord);
            OutputStream outputStream = new FileOutputStream(outputFile);
            IConverter converter = LocalConverter.builder().build();
            String fileTyle = docPath.substring(docPath.lastIndexOf("."), docPath.length());//获取文件类型
            if (".docx".equals(fileTyle)) {
                converter.convert(docxInputStream).as(DocumentType.DOCX).to(outputStream).as(DocumentType.PDF).execute();
            } else if (".doc".equals(fileTyle)) {
                converter.convert(docxInputStream).as(DocumentType.DOC).to(outputStream).as(DocumentType.PDF).execute();
            } else if (".xls".equals(fileTyle)) {
                converter.convert(docxInputStream).as(DocumentType.XLS).to(outputStream).as(DocumentType.PDF).execute();
            } else if (".xlsx".equals(fileTyle)) {
                converter.convert(docxInputStream).as(DocumentType.XLSX).to(outputStream).as(DocumentType.PDF).execute();
            }
            docxInputStream.close();
            outputStream.close();
//            inputWord.delete();
            System.out.println("pdf转换成功");
//            converter.shutDown();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }


    /**
     * 将生成的 Word 文档转换为 PDF 格式
     *
     * @param wordPath Word 文档路径
     * @param pdfPath  生成的 PDF 路径
     */
    public static void convertToPDF(String wordPath, String pdfPath) {

        String os = System.getProperty("os.name").toLowerCase();

        log.info("当前系统：{}", os);
        if (os.contains("win")) {
            // Windows操作系统
            documents4jWordToPdf(wordPath, pdfPath);
        } else if (os.contains("nix") || os.contains("nux") || os.contains("mac")) {
            // Unix/Linux/Mac操作系统
            linuxDocuments4jWordToPdf(new File(wordPath));
        } else {
            // 未知操作系统
            throw new RuntimeException("不支持当前操作系统转换文档");
        }


    }


    /**
     * yum install libreoffice
     * <p>
     * 通过documents4j 实现word转pdf -- linux 环境 需要有 libreoffice 服务
     *
     * @param file 源文件
     */
    public static File linuxDocuments4jWordToPdf(File file) {
        // 获取文件的绝对路径和目录路径
        String absolutePath = file.getAbsolutePath();
        String parentPath = file.getParent();

        // 构建LibreOffice的命令行工具命令
        String commands = "libreoffice --convert-to pdf "
                + absolutePath + " --outdir " + parentPath;
        // 执行转换命令
        try {
            boolean result = executeLinuxCmd(commands);
            if (result) {
                // 转换成功，返回转换后的PDF文件
                String pdfFilePath = parentPath + File.separator + file.getName().replaceAll("\\.(docx?|\\w+)$", "") + ".pdf";
                log.info(pdfFilePath);
                log.info(pdfFilePath);
                return new File(pdfFilePath);
            } else {
                return null;
            }

        } catch (Exception e) {
            // 转换失败
            log.error("Word文档转换为PDF失败，原因：执行命令时出现异常。", e);
            return null;
        }
    }


    /**
     * 执行命令行
     *
     * @param cmd 命令行
     * @return
     * @throws IOException
     */
    private static boolean executeLinuxCmd(String cmd) throws IOException {
        // 执行命令行工具命令
        Process process = Runtime.getRuntime().exec(cmd);
        try {
            process.waitFor();
        } catch (InterruptedException e) {
            log.error("执行 Linux 命令异常：", e);
            return false;
        }
        return true;
    }


}
